#include "domparser.h"


#include <QFile>
#include <QDebug>
#include <QTextStream>

#include "ethercatthread.h"

DomParser::DomParser( )
{
    m_file = NULL;
    md5Instance = MD5Check::getInstance();
}

DomParser::~DomParser()
{
    if(m_file)
    {
        closeXml();
        delete m_file;
        m_file = NULL;
    }
}

bool DomParser::openXml(QString filePath, QFile::OpenMode mode )
{
    closeXml();
    m_file = new QFile( filePath );
    m_filePath=filePath;

    if(m_filePath.isEmpty())
    {
        qDebug()<< "File path is empty!";
        return false;
    }
    if( !m_file->exists() )
    {
        qDebug() << "xml error:: not exists  : "<< m_filePath;
        return false;
    }
    if( !m_file->open( mode ) )
    {
        qDebug() << "xml error:: m_file open  : "<< m_filePath;
        return false;
    }
    //极少几率出现打开后无法 setContent的问题，添加打开等待；
    m_file->waitForReadyRead(1);

    //设置上下文
    QString errorStr;
    int errorLine=0;
    int errorColumn=0;

    //m_doc.clear();
    if( !m_doc.setContent( m_file, false, &errorStr, &errorLine, &errorColumn))
    {
        qDebug() << "xml error : XML文件格式不对或已损坏! "<<errorStr<<errorLine<< errorColumn <<filePath  ;
        m_file->close();
        return false;
    }

    m_root = m_doc.documentElement();
    if( m_doc.isNull() )
    {
        qDebug()<<"xml file is empty : "<< filePath;
        return false;
    }
    //    if(m_root.tagName()!= "Config"){
    //        qDebug()<<"不是程序所用的xml文件格式"<< m_root.tagName() ;
    //        return false;
    //    }else{
    //        qDebug()<<"xml open : "<< m_root.hasChildNodes();
    //    }

    return  true ;
}

void DomParser::closeXml( bool save )
{
    if(m_file==NULL)
        return;

    if( save )
    {
        m_file->resize(0);
        QTextStream out(m_file);
        out.setCodec("utf-8");
        // out<<m_doc.toString();
        m_doc.save(out,4,QDomNode::EncodingFromDocument);
        m_file->flush();
    }
    m_file->close();
    delete m_file;
    m_file = NULL;
}

QDomElement DomParser::addNode( QDomNode &pnode, QString nodeName, int val )
{
    return addNode(pnode,nodeName,QString::number(val));
}

QDomElement DomParser::addNode( QDomNode &pnode, QString nodeName, unsigned int val )
{
    return addNode(pnode,nodeName,QString::number(val));
}

QDomElement DomParser::addNode( QDomNode &pnode, QString nodeName, QString val )
{
    QDomElement idNode = m_doc.createElement(nodeName);
    QDomText idNodeTxt = m_doc.createTextNode(val);
    idNode.appendChild( idNodeTxt );
    pnode.appendChild( idNode );
    return idNode;
}

bool DomParser::readXml( QDomNode node ,char &val )
{
    bool ok;
    QString str = node.firstChild().nodeValue();

    if( str.indexOf("0x")>=0 ||  str.indexOf("#x")>=0 )
        val = str.remove("#x").toInt(&ok,16);
    else
        val = str.toInt(&ok);
    return ok;
}

bool DomParser::readXml( QDomNode node ,unsigned char &val )
{
    bool ok;
    QString str = node.firstChild().nodeValue();

    if( str.indexOf("0x")>=0 ||  str.indexOf("#x")>=0 )
        val = str.remove("#x").toInt(&ok,16);
    else
        val = str.toInt(&ok);
    return ok;
}

bool DomParser::readXml( QDomNode node ,int &val )
{
    bool ok;
    QString str = node.firstChild().nodeValue();
    if( str.indexOf("0x")>=0 ||  str.indexOf("#x")>=0 )
        val = str.remove("#x").toInt(&ok,16);
    else
        val = str.toInt(&ok);
    return ok;
}

bool DomParser::readXml( QDomNode node ,unsigned int &val )
{
    bool ok;
    QString str = node.firstChild().nodeValue();
    if( str.indexOf("0x")>=0 ||  str.indexOf("#x")>=0 )
        val = str.remove("#x").toUInt(&ok,16);
    else
        val = str.toUInt(&ok);
    return ok;
}

bool DomParser::readXml( QDomNode node ,float &val )
{
    bool ok;
    val = node.firstChild().nodeValue().toFloat(&ok);
    return ok;
}

bool DomParser::readXml( QDomNode node , double &val )
{
    bool ok;
    val = node.firstChild().nodeValue().toDouble(&ok);
    return ok;
}

bool DomParser::readXml( QDomNode node, QString &val )
{
    val = node.firstChild().nodeValue();
    return true;
}

void DomParser::writeXml( QDomNode node, char &val )
{
    writeXml(node, QString("%1").arg(val));
}

void DomParser::writeXml( QDomNode node, unsigned char &val )
{
    writeXml(node, QString("%1").arg(val));
}

void DomParser::writeXml( QDomNode node, int &val )
{
    writeXml(node, QString("%1").arg(val));
}

void DomParser::writeXml( QDomNode node, unsigned int &val )
{
    writeXml(node, QString("%1").arg(val));
}

void DomParser::writeXml( QDomNode node, double &val )
{
    writeXml(node, QString("%1").arg(val));
}

void DomParser::writeXml( QDomNode node, QString val )
{
    node.firstChild().setNodeValue( val );
}

void DomParser::writeXml(QString rootNode,QString nodeName, QString nodeValue, QString nodeAttr1, QString nodeValue1, QString nodeAttr2, QString nodeValue2, QString nodeAttr3, QString nodeValue3)
{

    QDomElement root = m_doc.documentElement();

    if(rootNode != root.tagName())
    {
        return ;
    }

   QDomNodeList list = root.childNodes();//获取所有节点
   for(int i = 0; i < list.count();i++)
   {
        QDomNode node = list.at(i);
        if(node.isElement())
        {
            if(node.nodeName() == nodeName)
            {
                QDomNode oldnode = node.firstChild();
                oldnode.setNodeValue(nodeValue);
            }

            if(node.hasAttributes())
            {
                QDomElement nodeElement = node.toElement();
                if(!(nodeElement.isNull()))
                {
                    if(nodeElement.hasAttribute(nodeAttr1))
                    {
                        qDebug() << "====nodeAttr1===="<<nodeAttr1<<"*****nodeValue1***"<<nodeValue1
                                    << "====nodeAttr2===="<<nodeAttr2<<"*****nodeValue2***"<<nodeValue2
                                    << "====nodeAttr3===="<<nodeAttr3<<"*****nodeValue3***"<<nodeValue3<<"\n\n\n";

                        nodeElement.setAttribute(nodeAttr1,nodeValue1);
                        nodeElement.setAttribute(nodeAttr2,nodeValue2);
                        nodeElement.setAttribute(nodeAttr3,nodeValue3);
                    }
                }
            }
        }
   }
}

void DomParser::setComponentVersion( QString className, QString date, QString version )
{ 
    pthread_mutex_lock(&pthreadMutex) ;
//    qLock.lock();

    QFile file(D_COMPONENT_VERSION_FILE) ;
    if(!file.exists())
    {
        file.open( QIODevice::WriteOnly );
        QByteArray buf("<?xml version='1.0' encoding='UTF-8'?>\n <Configinfo>\n<Parameters> </Parameters>\n</Configinfo>\n");
        file.write( buf, buf.size() );
        file.close();
    }

    bool ok= openXml(D_COMPONENT_VERSION_FILE , QFile::ReadWrite | QFile::Text);
    if( !ok )
    {
        qDebug()<<"open xml failed: setComponentVersion : "  << className;
        pthread_mutex_unlock(&pthreadMutex) ;
      //  qLock.unlock();
        return ;
    }
    //三级深度
    QDomNode node=findSubNode(m_root.childNodes().at(0), className, ok);
    // QDomNode node=findSubNode(m_root., className, ok);
    if( !ok || node.isNull() )
    {
        QDomNode pnode=m_root.childNodes().at(0);
        if( pnode.isNull() )
        {
                qDebug()<<"版本文件格式不正确! 自动修复! " ;
                closeXml(false);
                file.open( QIODevice::WriteOnly );
                QByteArray buf("<?xml version='1.0' encoding='UTF-8'?>\n <Configinfo>\n<Parameters> </Parameters>\n</Configinfo>\n");
                file.write( buf, buf.size() );
                file.close();
                openXml(D_COMPONENT_VERSION_FILE , QFile::ReadWrite | QFile::Text);
        }
        QDomElement ttNode  = addNode( pnode, className, version );
        ttNode.setAttribute("date", date);
    }else{
        node.firstChild().setNodeValue( version );
        node.toElement().setAttribute( "date", date );
    }
    //qDebug()<<"组件 :"<< className << "       , 版本 :"<< version << m_root.childNodes().at(0).nodeName();

    closeXml(true);

  //  qLock.unlock();
   pthread_mutex_unlock(&pthreadMutex) ;

#if MD5CHECK_DEBUG
    md5Instance->saveFile(D_COMPONENT_VERSION_FILE,GLOBAL_FILE_VALUE);
#endif
}

void DomParser::setComponentVersion( QString className, QString date, QString version , QString log )
{ 
    bool ok= openXml(D_COMPONENT_VERSION_FILE , QFile::ReadWrite | QFile::Text);
    if( !ok )
    {
        qDebug()<<"open xml failed: setComponentVersion : "  << className;
        return ;
    }
    //三级深度
    QDomNode node=findSubNode(m_root.childNodes().at(0), className, ok);
    // QDomNode node=findSubNode(m_root., className, ok);
    if( !ok || node.isNull() )
    {
        QDomNode pnode=m_root.childNodes().at(0);
        QDomElement ttNode  = addNode( pnode, className, log );
        ttNode.setAttribute("date", date);
        ttNode.setAttribute("version", version);
    }else{
        node.firstChild().setNodeValue( log );
        node.toElement().setAttribute( "date", date );
        node.toElement().setAttribute( "version", version );
    }

    closeXml(true);

#if MD5CHECK_DEBUG
    md5Instance->saveFile(D_COMPONENT_VERSION_FILE,GLOBAL_FILE_VALUE);
#endif

}


//查找节点的子节点
QDomNode DomParser::findSubNode( const QDomNode &node, QString name , bool &ok )
{
    QDomNodeList nodelist = node.childNodes();
    int len = nodelist.length();
    for(int i=0; i<len; i++)
    {
        if( nodelist.at(i).nodeName() == name )
        {
            ok=true;
            return  nodelist.at(i);
        }
    }
    // qDebug()<<" findSubNode: fail!"<< name <<len <<node.nodeName();
    ok = false;
    return QDomNode();
}

//在当前给的list中查找
QDomNode DomParser::findSibNode( const QDomNodeList &nodelist, QString name, bool &ok )
{
    int len = nodelist.length();
    for(int i=0; i<len; i++)
    {
        if( nodelist.at(i).nodeName() == name )
        {
            ok=true;
            return  nodelist.at(i);
        }
    }
    // qDebug()<<" findSibNode: fail!"<< name;
    ok=false;
    return QDomNode();
}


/*
 *    //获取树下某节点
 e.g.  test.xml
 <configinfo> //主干
      <Settings> //二级枝干(子树)
        <nodeTotal>7</nodeTotal>
      </Settings>

      <Dev5> //二级枝干(子树)
            <Alias>85</Alias>
            <Devtype>E_EK1100</Devtype>
            <Syncs> //三级枝干(子树)
                <count>2</count>
                <Sync0> //四级枝干(子树)
                    <index>2</index>
                    <type>EC_DIR_OUTNPUT</type>
                </Sync0>

                <Sync1>
                    <index>3</index>
                    <type>EC_DIR_INPUT</type>
                 </Sync1>
            </Syncs>

            <Pdos> //三级枝干(子树)
                <count>0</count>
            </Pdos>

            <Entries> //三级枝干(子树)
                <count>0</count>
            </Entries>
      </Dev5>
<configinfo>

1.     获取　节点 Sync0  ,
        那么　nodeTree ={ "Dev5", "Syncs", "Sync0" },    configinfo 是不需要的, 它属于一个文件标识，没有<configinfo>开头的文件将报错。

 2.   获取　节点 Syncs
       那么　nodeTree ={ "Dev5", "Syncs" },   configinfo 是不需要的

 */
QDomNode DomParser::findNode( const QStringList &nodeTree, bool &ok  )
{
    QDomNode node;
    ok=false;
    int len = nodeTree.size();
    if( len >0 )
    {
        ok=true;
        QDomNodeList nodes  = m_root.childNodes();
        QString nodeStr;
        foreach( nodeStr, nodeTree )
        {
            node = findSibNode( nodes, nodeStr, ok );
            if( node.nodeName() != nodeStr) {
                ok=false;
                break;
            }else{
                if( node.hasChildNodes() )
                {
                    nodes = node.childNodes();
                }else{
                    qDebug()<<"xml没有此节点名！"<<nodeStr;
                }
            }
        }
    }

    if(ok)
    {
        return node;
    }else{
        qDebug()<< "xml没有此节点:"<< nodeTree ;
        return QDomNode();
    }
}

